import re
from django import http
from django.shortcuts import redirect, render
from django.urls import reverse
from django.views import View
from QQLoginTool.QQtool import OAuthQQ
from django.conf import settings
from django.contrib.auth import login
from django_redis import get_redis_connection

import sinaweibopy3
from myitsdangerous import encode_signature_openid, decode_signature_openid
from oauth.models import OAuthQQUser, OAuthSinaUser
from response_code import RET
from users.models import User


class QQAuthURLView(View):
    def get(self, request):
        # 生成一个对象
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI)
        # 通过对象的get_qq_url获取二维码扫描地址
        login_url = oauth.get_qq_url()
        return redirect(login_url)


class OauthCallBackView(View):
    # 判断是否绑定
    def get(self, request):
        code = request.GET.get('code')
        if not code:
            return http.HttpResponseForbidden('code丢失了')
        # 生成一个对象
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI)

        access_token = oauth.get_access_token(code)
        openid = oauth.get_open_id(access_token)

        # 查询是否绑定过
        try:
            oauth_user = OAuthQQUser.objects.get(openid=openid)
        except Exception as e:
            # 加密
            openid = encode_signature_openid(openid)
            return render(request, 'oauth_callback.html', {'openid': openid})  # 返回一个openid给前端以便处理用户绑定业务
        # 如果绑定过了, 取用户 user
        user = oauth_user.user
        login(request, user)
        res = redirect(reverse('index'))
        res.set_cookie('username', user.username)
        return res

    def post(self, request):
        # 处理用户绑定业务
        openid = request.POST.get('openid')
        mobile = request.POST.get('mobile')
        pwd = request.POST.get('pwd')
        sms_code = request.POST.get('sms_code')
        if not all([openid, mobile, pwd, sms_code]):
            return http.HttpResponseForbidden('参数不全')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('手机号格式不正确')
        if not re.match(r'^[0-9A-Za-z]{8,20}$', pwd):
            return http.HttpResponseForbidden('密码格式有误')
        # 校验openid
        openid = decode_signature_openid(openid)
        if not openid:
            return http.HttpResponseForbidden('openid已失效')
        redis_conn = get_redis_connection('verify_code')
        redis_sms_code = redis_conn.get('sms_%s' % mobile).decode()
        if sms_code != redis_sms_code:
            return http.HttpResponseForbidden('短信验证码错误')
        try:
            # 如果手机号已经绑定了用户，则通过手机将QQ直接绑定该用户
            user = User.objects.get(mobile=mobile)
        except Exception as e:
            # 如果手机号未绑定用户，则用手机创建新用户并和QQ绑定
            user = User.objects.create_user(username=mobile, password=pwd, mobile=mobile)

        OAuthQQUser.objects.create(user=user, openid=openid)
        res = redirect(reverse('index'))
        login(request, user)
        res.set_cookie('username', user.username)
        return res


class SinaAuthURLView(View):
    def get(self, request):
        # 创建授权对象
        client = sinaweibopy3.APIClient(
            app_key=settings.APP_KEY,
            app_secret=settings.APP_SECRET,
            redirect_uri=settings.REDIRECT_URL)
        # get authorize url得到授权url
        # "https://api.weibo.com/oauth2/authorize?response_type=code&client_id=%s&redirect_uri=%s"
        login_url = client.get_authorize_url()
        # 返回url前端重定向,提供给用户做扫码认证
        return http.JsonResponse({'code': RET.OK, 'errmsg': "OK", 'login_url': login_url})


class SinaCallBackView(View):
    def get(self, request):
        # 用户做扫码认证后：http://www.meiduo.site:8000/sina_callback/?code=c783e3c2ed6821976a168f5d112c3f82
        code = request.GET.get('code')
        if not code:
            return http.HttpResponseForbidden('code丢失了')
        # 创建获取access_token的对象
        client = sinaweibopy3.APIClient(
            app_key=settings.APP_KEY,
            app_secret=settings.APP_SECRET,
            redirect_uri=settings.REDIRECT_URL)
        # 根据code获取access_token和uid值
        result = client.request_access_token(code)
        access_token = result.access_token
        openid = result.uid
        # 查询是否绑定过
        try:
            sinauser = OAuthSinaUser.get(uid=openid)
        except Exception as e:
            # 加密传输
            openid = encode_signature_openid(openid)
            context = {
                'openid': openid
            }
            return render(request, 'sina_callback.html', context)
        else:
            # 查询到授权对象，转到相关页面
            user = sinauser.user
            login(request, user)
            res = redirect('/')
            res.set_cookie('username', user.username)
            return res

    def post(self, request):
        openid = request.POST.get('openid')
        mobile = request.POST.get('mobile')
        pwd = request.POST.get('pwd')
        sms_code = request.POST.get('sms_code')
        if not all([openid, mobile, pwd, sms_code]):
            return http.HttpResponseForbidden('参数不全')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('手机号格式不正确')
        if not re.match(r'^[0-9A-Za-z]{8,20}$', pwd):
            return http.HttpResponseForbidden('密码格式有误')
        redis_conn = get_redis_connection('verify_code')
        redis_sms_code = redis_conn.get('sms_%s' % mobile).decode()
        if sms_code != redis_sms_code:
            return http.HttpResponseForbidden('短信验证码错误')
        # 验证：解密验证
        openid = decode_signature_openid(openid)
        if not openid:
            return http.HttpResponseForbidden('openid已失效')
        # 判断手机号是否已经绑定过
        try:
            # 如果手机号已经绑定了用户，则通过手机将微博直接绑定该用户
            user = User.objects.get(mobile=mobile)
        except Exception as e:
            # 如果手机号已经绑定了用户，则通过手机将微博直接绑定该用户
            # 正常情况下通过django自带的用户创建函数create_user进行用户创建，可将用户密码进行加密
            user = User.objects.create_user(username=mobile, password=pwd, mobile=mobile)
        OAuthSinaUser.objects.create(user=user, uid=openid)
        login(request, user)
        res = redirect('/')
        res.set_cookie('username', user.username)
        return res
